﻿using anydata.DataStorage;
using anydata.Entitys;
using anydata.Handlers;

using Microsoft.AspNetCore.SignalR;

using Newtonsoft.Json.Linq;

namespace anydata.DataShare
{
    public class DataHub : Hub
    {
        readonly DataProvider _data;
        readonly BucketManager _bucket;
        static SafeDictionary<string, TokenModel> _tokens = new SafeDictionary<string, TokenModel>();
        public DataHub(DataProvider data)
        {
            _data = data;
            _bucket = new BucketManager();
        }

        public override Task OnDisconnectedAsync(Exception? exception)
        {
            _tokens.Delete(Context.ConnectionId);
            return base.OnDisconnectedAsync(exception);
        }

        public Task TokenAuth(string accessToken)
        {
            try
            {
                _tokens.SetValue(Context.ConnectionId, TokenHanlder.Read(accessToken));
            }
            catch
            {
                Context.Abort();
            }
            return Task.CompletedTask;
        }

        public Task<OperateResult> ThingLoad(string belongId, DataSourceLoadOptions options)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.LoadAsync(token, string.Empty, options);
            });
        }

        public Task<OperateResult> ThingCreate(string belongId, string name)
        {
            return AuthExecute(belongId, (token) =>
            {
                return Task.FromResult(OperateResult.Success(new EntityBase()
                {
                    name = name,
                    id = SnowflakeIDcreator.nextId().ToString(),
                }));
            });
        }

        public Task<OperateResult> ThingDestroy(string belongId, List<string> ids)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.DestroyAsync(token, ids);
            });
        }

        public Task<OperateResult> CollectionList(string belongId)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.ListAsync(token);
            });
        }

        public Task<OperateResult> CollectionLoad(string belongId, string collName, DataSourceLoadOptions options)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.LoadAsync(token, collName, options);
            });
        }

        public Task<OperateResult> CollectionAggregate(string belongId, string collName, JToken options)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.AggregateAsync(token, collName, options);
            });
        }

        public Task<OperateResult> CollectionInsert(string belongId, string collName, JToken data)
        {
            return AuthExecute(belongId, async (token) =>
            {
                return await _data.InsertAsync(token, collName, data);
            });
        }

        public Task<OperateResult> CollectionUpdate(string belongId, string collName, CollectUpdateData update)
        {
            return AuthExecute(belongId, async (token) =>
            {
                return await _data.UpdateAsync(token, collName, update);
            });
        }

        public Task<OperateResult> CollectionReplace(string belongId, string collName, JToken replace)
        {
            return AuthExecute(belongId, async (token) =>
            {
                return await _data.ReplaceAsync(token, collName, replace);
            });
        }

        public Task<OperateResult> CollectionSetFields(string belongId, string collName, CollectSetFields collSet)
        {
            return AuthExecute(belongId, async (token) =>
            {
                return await _data.SetFieldsAsync(token, collName, collSet);
            });
        }

        public Task<OperateResult> CollectionRemove(string belongId, string collName, JToken match)
        {
            return AuthExecute(belongId, async (token) =>
            {
                return await _data.RemoveAsync(token, collName, match);
            });
        }
        public Task<OperateResult> ObjectList(string belongId, string objectKey)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.ListAsync(token, objectKey);
            });
        }

        public Task<OperateResult> ObjectGet(string belongId, string key)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.GetAsync(token, key);
            });
        }
        public Task<OperateResult> ObjectSet(string belongId, string key, ObjectSetData setData)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.SetAsync(token, key, setData);
            });
        }

        public Task<OperateResult> ObjectDelete(string belongId, string key)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _data.DeleteAsync(token, key);
            });
        }

        public Task<OperateResult> BucketOpreate(string belongId, BucketItemData item)
        {
            return AuthExecute(belongId, (token) =>
            {
                return _bucket.Execute(token, item);
            });
        }

        public Task<HubFileResult> BucketShare(string link, long startIndex)
        {
            if (link.Contains("0")) {
                link = link.Substring(link.IndexOf("0") + 1);
            }
            var key = link.Substring(10).FromBase32().ToBase64();
            return _bucket.LoadFileRange(key, startIndex);
        }

        private Task<OperateResult> AuthExecute(string id, Func<TokenModel, Task<OperateResult>> operate)
        {
            var local = _tokens.GetValue(Context.ConnectionId);
            if (local != default)
            {
                var token = new TokenModel()
                {
                    UserId = local.UserId,
                    BelongId = local.BelongId,
                };
                if (ulong.TryParse(id, out var belongId) && belongId > 0)
                {
                    token.BelongId = belongId;
                }
                return operate(token).TryExecute();
            }
            return Task.FromResult(OperateResult.Faild("请先鉴权"));
        }
    }
}
